# Wireshark - Network traffic analyzer
# By Gerald Combs <gerald@wireshark.org>
# Copyright 1998 Gerald Combs
#
# SPDX-License-Identifier: GPL-2.0-or-later

import os
import re
import subprocess


# For text colouring/highlighting.
class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    ADDED = '\033[45m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'


def isBinaryFile(filename):
    abs_path = os.path.abspath(filename)
    if os.path.join('test', 'captures') in abs_path:
        return True
    # TODO: other paths or file extensions that won't be textual?
    else:
        return False


def isDissectorFile(filename):
    if not filename.endswith('.c'):
        return False

    abs_path = os.path.abspath(filename)
    if os.path.join('plugins', 'epan') in abs_path:
        return True
    elif os.path.join('epan', 'dissectors') in abs_path:
        p = re.compile(r'.*(packet|file)-.*\.c$')
        return p.match(filename)
    else:
        return False


# Test for whether the given file was automatically generated.
def isGeneratedFile(filename):
    # Check file exists - e.g. may have been deleted in a recent commit.
    if not os.path.exists(filename):
        return False

    if filename.endswith('packet-asterix.c'):
        return True

    # Open file
    f_read = open(os.path.join(filename), 'r',
                  encoding="utf8", errors="ignore")
    lines_tested = 0
    for line in f_read:
        # The comment to say that its generated is near the top, so give up
        # once get a few lines down.
        if lines_tested > 10:
            f_read.close()
            return False
        if ('Generated automatically' in line or
                'Generated Automatically' in line or
                'Autogenerated from' in line or
                'is autogenerated' in line or
                'automatically generated by Pidl' in line or
                'Created by: The Qt Meta Object Compiler' in line or
                'This file was generated' in line or
                'This filter was automatically generated' in line or
                'This file is auto generated' in line or
                'this file is automatically generated' in line):

            f_read.close()
            return True
        lines_tested = lines_tested + 1

    # OK, looks like a hand-written file!
    f_read.close()
    return False


def removeComments(code_string):
    # C-style comment
    code_string = re.sub(re.compile(r"(?<!/)/\*.*?\*/", re.DOTALL), "",
                         code_string)
    # C++-style comment
    # Avoid matching // where it is allowed, e.g.,  https://www... or file:///...
    code_string = re.sub(re.compile(r"(?<!:)(?<!/)(?<!\")(?<!\"\s\s)(?<!file:/)(?<!\.)(?<!\,\s)(?<!\\n)//.*?\n"),
                         "", code_string)
    # Ignored region
    code_string = re.sub(re.compile(r"#if 0.*?#endif", re.DOTALL), "", code_string)

    return code_string


def findDissectorFilesInFolder(folder, recursive=False, include_generated=True):
    dissector_files = []

    if recursive:
        for root, subfolders, files in os.walk(folder):
            for f in files:
                f = os.path.join(root, f)
                dissector_files.append(f)
    else:
        for f in sorted(os.listdir(folder)):
            filename = os.path.join(folder, f)
            dissector_files.append(filename)

    return [x for x in dissector_files if
            isDissectorFile(x) and not isBinaryFile(x) and
            (include_generated or not isGeneratedFile(x))]


def getFilesFromCommits(commits, onlyDissectors=True):
    # Get files affected by specified number of commits.
    command = ['git', 'diff', '--name-only', '--diff-filter=d', 'HEAD~' + commits]
    files = [f.decode('utf-8')
             for f in subprocess.check_output(command).splitlines()]
    files = list(filter(lambda f: not isBinaryFile(f), files))

    # Only interested in dissector files?
    if onlyDissectors:
        files = list(filter(lambda f: isDissectorFile(f), files))
    return files


def getFilesFromOpen(onlyDissectors=True):
    command = ['git', 'diff', '--name-only', '--diff-filter=d']
    files = [f.decode('utf-8')
             for f in subprocess.check_output(command).splitlines()]
    files = list(filter(lambda f: isDissectorFile(f), files))
    # Staged changes.
    command = ['git', 'diff', '--staged', '--name-only', '--diff-filter=d']
    files_staged = [f.decode('utf-8')
                    for f in subprocess.check_output(command).splitlines()]
    # Only interested in dissector files.
    files_staged = list(filter(lambda f: isDissectorFile(f), files_staged))
    for f in files_staged:
        if f not in files:
            files.append(f)
    files = list(filter(lambda f: not isBinaryFile(f), files))
    # Only interested in dissector files?
    if onlyDissectors:
        files = list(filter(lambda f: isDissectorFile(f), files))
    return files
